<!DOCTYPE html>
<head>
  <title>MyVue</title>
</head>
<style>
  #app {
    text-align: center;
  }
</style>
<body>
	<div id="app">
	    <form>
	      <input type="text"  v-model="number">
	      <button type="button" v-click="increment">增加</button>
	    </form>
	    <h3 v-bind="number"></h3>
	</div>
</body>

<script>
    function MyVue(options) {
    	this._init(options);
    }

    MyVue.prototype._init=function(options){
    	this.$options = options;
    	this.$el = document.querySelector(options.el);
    	this.$data = options.data;
    	this.$methods = options.methods;

    	this._binding = {};

    	this._obverse(this.$data);
    	this._compile(this.$el);
    }

    MyVue.prototype._obverse=function(obj){
    	Object.keys(obj).forEach((key)=>{
    		if(obj.hasOwnProperty(key)){

    			this._binding[key]={
    				_directives:[]
    			}

    			var value = obj[key];
    			if(typeof value === 'object'){
    				this._obverse(value)
    			}
    			var binding = this._binding[key];

    			Object.defineProperty(this.$data,key,{
    				enumerable:true,
    				configurable:true,
    				get:function(){
    					console.log(`获取${value}`)
    					return value
    				},
    				set:function(newVal){
    					if(value!=newVal){
    						console.log(`更新${newVal}`)
    						value = newVal
    						binding._directives.forEach(function(item){
    							item.update();
    						})
    					}
    				}
    			})
    		}
    	})
    }

    MyVue.prototype._compile=function(root){
    	var _this =this;
    	var nodes =root.children; 
    	for(var i=0;i<nodes.length;i++){
    		var node = nodes[i]
    		if(node.children.length){
    			this._compile(node);
    		}

    		if(node.hasAttribute('v-click')){
    			node.onclick=(function(){
    				var attrVal = nodes[i].getAttribute('v-click');
    				return _this.$methods[attrVal].bind(_this.$data);
    			})()
    		}


    		if (node.hasAttribute('v-model') && (node.tagName == 'INPUT' || node.tagName == 'TEXTAREA')) {
		        node.addEventListener('input', (function(key) {  
		            var attrVal = node.getAttribute('v-model');
		            _this._binding[attrVal]._directives.push(new Watcher(  
			            'input',
			            node,
			            _this,
			            attrVal,
			            'value'
		            ))

		            return function() {
		              _this.$data[attrVal] =  nodes[key].value;
		            }
		        })(i));
		    }

		    if (node.hasAttribute('v-bind')) {
		        var attrVal = node.getAttribute('v-bind');
		        _this._binding[attrVal]._directives.push(new Watcher(
			        'text',
			        node,
			        _this,
			        attrVal,
			        'innerHTML'
		        ))
		    }
    	}
    }

    function Watcher(name,el,vm,exp,attr){
    	this.name = name;
    	this.el = el;
    	this.vm = vm;
    	this.exp = exp;
    	this.attr = attr;

    	this.update()
    }

    Watcher.prototype.update=function(){
    	this.el[this.attr] =this.vm.$data[this.exp];
    }


    var app = new MyVue({
      el:'#app',
      data: {
        number: 0,
        count:99
      },
      methods: {
        increment: function() {
          this.number ++;
        },
      }
    })

</script>